Skip to content

Conversation

@machin0r
Copy link

Add support for functools.lru_cache decorator, Fixes #16261

Description

Problem: Functions decorated with @lru_cache lose their original type signatures, preventing mypy from validating function calls properly.

Solution:

  • Added functools_lru_cache_callback to preserve function signatures for @lru_cache
  • Added lru_cache_wrapper_call_callback to validate calls to cached functions
  • Registered callbacks in DefaultPlugin for both decorator creation and wrapper calls
  • Added tests for different lru_cache patterns

Supported patterns:

  • @lru_cache - bare decorator
  • @lru_cache() - empty parentheses
  • @lru_cache(maxsize=128) - parameters

Example

Before:

from functools import lru_cache
@lru_cache()
def f(x: int) -> str:
    return str(x)

f()  # No error, mypy can't validate arguments
f("str")  # No error, mypy can't check types

After:
from functools import lru_cache
@lru_cache()
def f(x: int) -> str:
    return str(x)

f()  # error: Missing positional argument "x" in call to "f"  [call-arg]
f("str")  # error: Argument 1 to "f" has incompatible type "str"; expected "int"  [arg-type]

Files changed:

  • mypy/plugins/functools.py - Implementation
  • mypy/plugins/default.py - Plugin registration
  • test-data/unit/check-functools.test - Test cases
  • test-data/unit/lib-stub/functools.pyi - Type stub updates

@machin0r machin0r marked this pull request as draft July 13, 2025 17:14
@machin0r machin0r marked this pull request as ready for review July 13, 2025 17:47
@github-actions

This comment has been minimized.

@machin0r machin0r force-pushed the implement-lru-cache-support branch from 9aa3d9f to a4372e8 Compare July 13, 2025 18:35
@machin0r machin0r marked this pull request as draft July 13, 2025 18:46
 - Add lru_cache callback to functools plugin for type validation
 - Register callbacks in default plugin for decorator and wrapper calls
 - Support different lru_cache patterns: @lru_cache, @lru_cache(), @lru_cache(maxsize=N)

Fixes issue python#16261
@machin0r machin0r force-pushed the implement-lru-cache-support branch from a4372e8 to d9d5d00 Compare July 13, 2025 18:49
@github-actions
Copy link
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

psycopg (https://github.com/psycopg/psycopg)
+ psycopg/psycopg/rows.py:136: error: Argument 2 to "_make_nt" has incompatible type "*Generator[bytes | None, None, None]"; expected "bytes"  [arg-type]

archinstall (https://github.com/archlinux/archinstall)
+ archinstall/lib/interactions/general_conf.py:160: error: Argument 1 to "list_available_packages" has incompatible type "tuple[Repository, ...]"; expected "tuple[Repository]"  [arg-type]

mitmproxy (https://github.com/mitmproxy/mitmproxy)
+ mitmproxy/tools/console/common.py:808: error: Argument "request_timestamp" to "format_dns_flow" has incompatible type "float | None"; expected "float"  [arg-type]
+ mitmproxy/tools/console/common.py:816: error: Argument "error_message" to "format_dns_flow" has incompatible type "str | None"; expected "str"  [arg-type]

core (https://github.com/home-assistant/core)
+ homeassistant/components/xiaomi_aqara/config_flow.py:216: error: Argument 1 to "format_mac" has incompatible type "str | None"; expected "str"  [arg-type]
+ homeassistant/components/mqtt_room/sensor.py:199: error: Argument 1 to "_slugify_upper" has incompatible type "Any | None"; expected "str"  [arg-type]
+ homeassistant/components/esphome/manager.py:468: error: Argument 1 to "format_mac" has incompatible type "str | None"; expected "str"  [arg-type]
+ homeassistant/components/esphome/light.py:182: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:191: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:202: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:211: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:212: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:217: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:229: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:246: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:251: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:265: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/light.py:346: error: Argument 1 to "_filter_color_modes" has incompatible type "tuple[Any, ...]"; expected "list[Any]"  [arg-type]
+ homeassistant/components/esphome/config_flow.py:541: error: Argument 1 to "format_mac" has incompatible type "str | None"; expected "str"  [arg-type]
+ homeassistant/components/esphome/config_flow.py:591: error: Argument 1 to "format_mac" has incompatible type "str | None"; expected "str"  [arg-type]

schemathesis (https://github.com/schemathesis/schemathesis)
+ src/schemathesis/specs/openapi/stateful/__init__.py:127: error: Argument 2 to "make_response_filter" has incompatible type "tuple[Any, ...]"; expected "Iterator[str]"  [arg-type]
+ src/schemathesis/specs/openapi/stateful/__init__.py:127: note: "tuple" is missing following "Iterator" protocol member:
+ src/schemathesis/specs/openapi/stateful/__init__.py:127: note:     __next__

ibis (https://github.com/ibis-project/ibis)
+ ibis/backends/tests/test_temporal.py:2227: error: Argument "exclude" to "_get_backend_names" has incompatible type "tuple[str, str]"; expected "tuple[str]"  [arg-type]
+ ibis/backends/tests/test_temporal.py:2245: error: Argument "exclude" to "_get_backend_names" has incompatible type "tuple[str, str, str, str, str, str]"; expected "tuple[str]"  [arg-type]

@machin0r machin0r marked this pull request as ready for review July 13, 2025 19:46
@cdce8p cdce8p added the topic-plugins The plugin API and ideas for new plugins label Jul 15, 2025
@machin0r
Copy link
Author

Hi! This PR has been open for a while now, I just wanted to check if there's anything I can clarify or improve to help with review.

Happy to make any changes needed!

@machin0r
Copy link
Author

Hey just following up on this again, is there anything I can do to help move this along?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic-plugins The plugin API and ideas for new plugins

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parameters for a call to a function wrapped in a lru_cache are not checked

2 participants